from wormbane.model.corpse import Corpse
from wormbane.model.thing import Thing
from wormbane.util.format import add_indefinite_article

import random

class Monster(Thing):
    is_monster = True
    race = None
    gender = 'random'
    size = 'medium'
    capacity = 50
    health = 1
    damage = 0
    protection = 0
    hallucinating = 0
    time = 0

    def __init__(self, **kwargs):
        Thing.__init__(self, **kwargs)
        self.eq = dict()
        if self.gender == 'random':
            self.gender = random.choice(('male', 'female'))

    def __str__(self):
        if self.name:
            return self.name
        return add_indefinite_article(self.race.name)

    def create_corpse(self):
        return self.race.create_corpse(monster = self)

    def create_treasure(self):
        return self.race.create_treasure()

    @property
    def char(self):
        return self.race.char

    @property
    def color(self):
        return self.race.color

    @property
    def top_eq(self):
        for slot in self.top_slots:
            eq = self.eq.get(slot)
            if eq:
                return eq
        return None

    @property
    def total_damage(self):
        return self.damage + sum(getattr(item, 'damage', 0)
                                 for item in self.wielded)

    @property
    def total_protection(self):
        return self.protection + sum(item.protection for item in self.worn)

    def move_to(self, env):
        old_level = self.level_env
        Thing.move_to(self, env)
        new_level = self.level_env
        if new_level != old_level:
            if old_level:
                old_level.remove_monster(self)
            if new_level:
                new_level.add_monster(self)

    def wield(self, item):
        if item:
            if not item.is_item or item.env != self:
                raise ValueError('only carried items can be wielded')
            if item.wielded:
                raise ValueError('that item is already wielded')
            if self.weapon:
                raise StateError('already wielding something')
            if item.is_weapon and item.two_handed and 'shield' in self.eq:
                raise StateError('cannot wield a two-handed weapon while '
                                 'wearing a shield')
            self.eq['weapon'] = item
            item.wielded = True
        else:
            item = self.eq.pop('weapon', None)
            if not item:
                raise StateError('not wielding anything')
            item.wielded = False

    def wear(self, armor):
        if not armor or not armor.is_armor or armor.env != self:
            raise ValueError('only carried armor pieces can be worn')
        if armor.worn:
            raise ValueError('that armor piece is already worn')
        if armor.slot in self.eq:
            raise StateError('already wearing an armor piece in that slot')
        if (armor.slot == 'shield' and self.weapon and self.weapon.is_weapon
            and self.weapon.two_handed):
            raise StateError('cannot wear a shield while wielding a '
                             'two-handed weapon')
        self.eq[armor.slot] = armor
        armor.worn = True

    def remove(self, armor):
        if not armor or not armor.is_armor or armor.env != self:
            raise ValueError('only carried armor pieces can be removed')
        if not armor.worn:
            raise ValueError('that armor piece is not worn')
        del self.eq[armor.slot]
        armor.worn = False

    def remove_inv(self, thing):
        if thing.is_item and thing.wielded:
            self.wield(None)
        if thing.is_armor and thing.worn:
            self.remove(thing)
        Thing.remove_inv(self, thing)

    @property
    def weapon(self):
        return self.eq.get('weapon')

    @property
    def pick(self):
        weapon = self.weapon
        return weapon if weapon and weapon.kind == 'pick' else None

    @property
    def slots(self):
        return self.race.slots

    @property
    def top_slots(self):
        return self.race.top_slots

    @property
    def size(self):
        return self.race.size

class StateError(Exception):
    pass
